﻿using System;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Collections.Generic;
using Technullogy.Web.UI.Weather.TechnullogyWeather;
using Technullogy.Web.UI.TwcWeather;
using System.Linq;

namespace Technullogy.Web.UI.Weather
{
    [ToolboxData("<{0}:Weather runat=\"server\"></{0}:Weather>")]
    public class Weather : CompositeControl
    {
        #region Declarations
        private const String IMAGE_NAMESPACE = "Technullogy.Web.UI.Weather.Images";
        private const String TWC_LOGO = "Technullogy.Web.UI.Weather.Images.twcLogo.png";
        private const String TWC_URI = "http://xoap.weather.com/weather/local/{0}?cc=*&par={1}&prod=xoap&key={2}&dayf=5&link=xoap&unit={3}";
        private const String LINE_BREAK = "\r\n";
        private const String FORECAST_TOOLTIP = "{0}{1}Sunrise: {2}{1}Sunset: {3}{1}Humidity: {4}%{1}Chance for precipitation: {5}%";
        #endregion

        #region Properties
        /// <summary> Gets or sets Weather.com LicenseKey as String
        /// </summary>
        [Bindable(true), Category("Behavior"), Description("TWC License Key. Visit http://www.weather.com/services/xmloap.html to register")]
        public String LicenseKey { get; set; }

        /// <summary> Gets or sets Weather.com PartnerId as String
        /// </summary>
        [Bindable(true), Category("Behavior"), Description("TWC Partner ID. Visit http://www.weather.com/services/xmloap.html to register")]
        public String PartnerId { get; set; }

        /// <summary> Gets or sets Weather.com LocationId as String
        /// </summary>
        [Bindable(true), Category("Behavior"), DefaultValue("72745"), Description("Default LocationId for displaying weather")]
        public String LocationId
        {
            get
            {
                if (ViewState["LocationId"] == null)
                    ViewState["LocationId"] = "72745";
                return ViewState["LocationId"].ToString();
            }
            set
            {
                ViewState["LocationId"] = value;
            }
        }

        /// <summary> Arraylist of search results
        /// </summary>
        private static List<LocationDetail> SearchResults
        {
            get
            {
                if (HttpContext.Current.Session["SearchResults"] != null)
                    return (List<LocationDetail>)HttpContext.Current.Session["SearchResults"];
                else
                    return new List<LocationDetail>();
            }
            set
            {
                HttpContext.Current.Session["SearchResults"] = value;
            }
        }

        private bool _enableCaching = true;
        /// <summary> Gets or sets EnableCaching as boolean
        /// </summary>
        [Description("Cache weather data by LocationId (per TWCi agreement)"), DefaultValue(true)]
        public bool EnableCaching 
        {
            get { return _enableCaching; }
            set { _enableCaching = value; }
        }

        private Units _units = Units.Imperial;
        /// <summary> Gets or sets Measurement Units as Units
        /// </summary>
        [Bindable(true), Category("Behavior"), DefaultValue(Units.Imperial), Description("Imperial or Metric")]
        public Units DisplayUnits 
        {
            get { return _units; }
            set { _units = value; }
        }
        
        private bool _showDayInForecast = true;
        /// <summary> Gets or sets ShowDateInForecast as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show days in the forecast header")]
        public bool ShowDayInForecast 
        {
            get { return _showDayInForecast; }
            set { _showDayInForecast = value; }
        }
        
        private bool _showForecast = true;
        /// <summary> Gets or sets ShowForecast as boolean
        /// </summary>
        [Category("Appearance"), DefaultValue(true), Description("Whether or not to show forecast information")]
        public bool ShowForecast 
        {
            get { return _showForecast; }
            set { _showForecast = value; }
        }
        
        private bool _showWindChill = true;
        /// <summary> Gets or sets ShowWindChill as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true)]
        public bool ShowWindChill 
        {
            get { return _showWindChill; }
            set { _showWindChill = value; }
        }
        
        private bool _showWindSpeedAndDirection = true;
        /// <summary> Gets or sets ShowWindSpeedAndDirection as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true)]
        public bool ShowWindSpeedAndDirection 
        {
            get { return _showWindSpeedAndDirection; }
            set { _showWindSpeedAndDirection = value; }
        }
        
        private bool _showHumidity = true;
        /// <summary> Gets or sets ShowHumidity as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show humidity")]
        public bool ShowHumidity 
        {
            get { return _showHumidity; }
            set { _showHumidity = value; }
        }
        
        private bool _showDewpoint = true;
        /// <summary> Gets or sets ShowDewpoint as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show the dewpoint")]
        public bool ShowDewpoint 
        {
            get { return _showDewpoint; }
            set { _showDewpoint = value; }
        }
        
        private bool _showVisibility = true;
        /// <summary> Gets or sets ShowVisibility as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show the visibility")]
        public bool ShowVisibility 
        {
            get { return _showVisibility; }
            set { _showVisibility = value; }
        }
        
        private bool _showChanceForPrecipitation = true;
        /// <summary> Gets or sets ShowVisibility as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show the chance for precipitation")]
        public bool ShowChanceForPrecipitation 
        {
            get { return _showChanceForPrecipitation; }
            set { _showChanceForPrecipitation = value; }
        }
        
        private bool _showBarometer = true;
        /// <summary> Gets or sets ShowBarometer as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show barometric pressure")]
        public bool ShowBarometer 
        {
            get { return _showBarometer; }
            set { _showBarometer = value; }
        }
        
        private bool _showUvIndex = true;
        /// <summary> Gets or sets ShowUvIndex as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show the UV index")]
        public bool ShowUvIndex 
        {
            get { return _showUvIndex; }
            set { _showUvIndex = value; }
        }
        
        private bool _showLinks = true;
        /// <summary> Gets or sets ShowLinks as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show additional TWC hyperlinks")]
        public bool ShowLinks 
        {
            get { return _showLinks; }
            set { _showLinks = value; }
        }
        
        private int _forecastDaysToDisplay = 5;
        /// <summary> Gets or sets ForecastDaysToDisplay as Integer
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(5), Description("Number of days to show in forecast (Max = 5)")]
        public int ForecastDaysToDisplay 
        {
            get { return _forecastDaysToDisplay; }
            set 
            {
                if (value >= 1 && value <= 5)
                    _forecastDaysToDisplay = value;
            }
        }

        private ImageSize _todayIconSize = ImageSize.Large;
        /// <summary> Gets or sets TodayIconSize as ImageSize
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(ImageSize.Large), Description("Size of main weather icon")]
        public ImageSize TodayIconSize 
        {
            get { return _todayIconSize; }
            set { _todayIconSize = value; }
        }
        
        private ImageSize _forecastIconSize = ImageSize.Small;
        /// <summary> Gets or sets ForecastIconSize as ImageSize
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(ImageSize.Small), Description("Size of forecast icons")]
        public ImageSize ForecastIconSize 
        {
            get { return _forecastIconSize; }
            set { _forecastIconSize = value; }
        }
        
        private bool _showTwcLogo = true;
        /// <summary> Gets or sets ShowTwcLogo as boolean
        /// </summary>
        [Bindable(true), Category("Appearance"), DefaultValue(true), Description("Whether or not to show the TWC logo")]
        public bool ShowTwcLogo 
        {
            get { return _showTwcLogo; }
            set { _showTwcLogo = value; }
        }

        private WeatherSkin _embeddedSkin = WeatherSkin.Blue;
        [Description("The embedded skin used by Technullogy Weather. Set EnableEmbeddedSkins to true to use embedded skins.  Default is Blue."), Category("Appearance"), DefaultValue(WeatherSkin.Blue)]
        public WeatherSkin EmbeddedSkin
        {
            get { return _embeddedSkin; }
            set { _embeddedSkin = value; }
        }
        [Description("The custom skin used by Technullogy Weather. Set EnableEmbeddedSkins to false to use custom skins."), Category("Appearance")]
        public String CustomSkin { get; set; }

        private bool _enableEmbeddedSkins = true;
        [Description("Whether to use embedded skins or not.  Set to false to use a custom skin."), Category("Appearance"), DefaultValue(true)]
        public bool EnableEmbeddedSkins
        {
            get
            {
                return _enableEmbeddedSkins;
            }
            set
            {
                _enableEmbeddedSkins = value;
            }
        }

        private String Skin
        {
            get
            {
                if (EnableEmbeddedSkins)
                    return _embeddedSkin.ToString();
                else
                    return CustomSkin;
            }
        }

        private weather MyTwcWeather { get; set; }

        private Char DisplayUnitsChar
        {
            get
            {
                if (DisplayUnits == Units.Imperial)
                    return 'i';
                else
                    return 'm';
            }
        }

        private Uri TwcUri
        {
            get 
            {
                return new Uri(String.Format(TWC_URI, LocationId, PartnerId, LicenseKey, DisplayUnitsChar, UriKind.Absolute));
            }
        }
        #endregion

        #region Methods
       // Initizlize & Add controls
        private TextBox txtSearch;
        private Button btnSearch;
        private RadioButtonList rblDisplayUnits;
        private LinkButton lbLocation;
        private PlaceHolder phSearchResults;

        private void InitializeControls()
        {
            // Search TextBox
            txtSearch = new TextBox() { ID = "txtSearch" };
            Controls.Add(txtSearch);

            // Search Button
            btnSearch = new Button()
            {
                ID = "btnSearch",
                Text = "Go",
                ValidationGroup = "TechnullogyWeather"
            };
            Controls.Add(btnSearch);
            btnSearch.Click += btnSearch_Click;

            // DisplayUnits RadioButtonList
            rblDisplayUnits = new RadioButtonList()
            {
                ID = "rblDisplayUnits",
                AutoPostBack = true,
                RepeatDirection = RepeatDirection.Horizontal
            };
            rblDisplayUnits.Items.Clear();
            rblDisplayUnits.Items.Add(new ListItem("Imperial", Units.Imperial.ToString()));
            rblDisplayUnits.Items.Add(new ListItem("Metric", Units.Metric.ToString()));
            rblDisplayUnits.SelectedValue = DisplayUnits.ToString();
            Controls.Add(rblDisplayUnits);

            // PlaceHolder for SearchResults
            phSearchResults = new PlaceHolder() { ID = "phSearchResults" };
            Controls.Add(phSearchResults);

            try
            {
                SearchResults.ForEach(location =>
                {
                    lbLocation = new LinkButton 
                    { 
                        ID = location.LocationId, 
                        CommandArgument = location.LocationId, 
                        Text = String.Format("<br />{0}", location.LocationName), 
                        ValidationGroup = "TechnullogyWeatherSearchResults" 
                    };
                    phSearchResults.Controls.Add(lbLocation);
                    lbLocation.Click += lbLocation_Click;
                });
            }
            catch (Exception)
            {
            }
            
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            InitializeControls();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            DisplayUnits = (rblDisplayUnits.SelectedValue == Units.Imperial.ToString()) ? Units.Imperial : Units.Metric;
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            // The LicenseId and PartnerId properties must be set
            if (String.IsNullOrEmpty(PartnerId) || String.IsNullOrEmpty(LicenseKey))
            {
                writer.Write("<br /><center><b>Technullogy Weather Error!</b><br /><br />");
                writer.Write("Weather.com requires a valid LicenseKey and PartnerId.<br /><br />");
                writer.Write("<a href=\"http://www.weather.com/services/xmloap.html\">Visit http://www.weather.com/services/xmloap.html to register.</a></center><br />");
                return;
            }
            try
            {
                // Load XmlDocument from TWC URI
                XmlDocument xmlDoc = WeatherManager.LoadTwcIntoXmlDoc(TwcUri, EnableCaching, LocationId, DisplayUnits);

                // Deserialize xml to weather object
                MyTwcWeather = TwcWeatherManager.GetTwcWeather(xmlDoc);

                // Write contents 
                StringBuilder weatherText = GetWeatherText(MyTwcWeather);
                writer.Write(weatherText.ToString());

                // Add controls
                rblDisplayUnits.RenderControl(writer);
                txtSearch.RenderControl(writer);
                btnSearch.RenderControl(writer);
                phSearchResults.RenderControl(writer);

                if (ShowLinks | ShowTwcLogo)
                {
                    writer.Write(String.Format("<hr><table class=\"{0}WcFooter\"><tr><td>", Skin));

                    // Show Links?
                    if (ShowLinks)
                        writer.Write(String.Format("Featured on <i>weather.com&reg;</i>:<br />{0}", GetLinks(xmlDoc)));

                    String WeatherLogo = String.Empty;
                    if (ShowTwcLogo)
                    {
                        String twcLogo = Page.ClientScript.GetWebResourceUrl(typeof(WeatherForecast), TWC_LOGO);
                        WeatherLogo = String.Format("<img src=\"{0}\" alt=\"Weather.com\" border=\"0\" />", twcLogo);

                        writer.Write("<br />Data provided by <a href=\"http://www.weather.com\">Weather.com</a></td>");
                        writer.Write(String.Format("<td class=\"{0}Wc\"><br /><a href=\"http://www.weather.com\">{1}</a>", Skin, WeatherLogo));
                    }

                    writer.Write("</td></tr></table>");
                }
            }
            catch (Exception ex)
            {
                // Strange things are afoot
                writer.Write(String.Format("<br /><br />There was a problem loading the weather data.<br /><br />{0}<br />{1}<br />{2}", ex.Message, ex.Source.ToString(), ex.StackTrace.ToString()));
            }
            
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (EnableEmbeddedSkins)
            {
                // Register CSS
                String styleSheet = String.Format("Technullogy.Web.UI.Weather.Skins.{0}.styles.css", Skin);
                String styleSheetLocation = Page.ClientScript.GetWebResourceUrl(typeof(WeatherForecast), styleSheet);
                String cssLink = String.Format("<link rel=\"stylesheet\" text=\"text/css\" href=\"{0}\" />", styleSheetLocation);
                if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(), styleSheet))
                    Page.ClientScript.RegisterClientScriptBlock(GetType(), styleSheet, cssLink);
            }
        }

        void lbLocation_Click(object sender, EventArgs e)
        {
            LocationId = ((LinkButton)sender).CommandArgument;
            SearchResults = new List<LocationDetail>();
            InitializeControls();
        }

        void btnSearch_Click(object sender, EventArgs e)
        {
            PerformLocationSearch(txtSearch.Text);
            if (SearchResults.Count > 1)
                InitializeControls();
        }

        private StringBuilder GetWeatherText(weather twcWeather)
        {
            StringBuilder weatherContent = new StringBuilder();
            WeatherOutlook outlook = new WeatherOutlook(twcWeather);

            if (String.IsNullOrEmpty(outlook.Location))
                weatherContent.Append("<br /><center><b>Location not found. Please try again.</b></center><br />");
            else
            {
                // Images for forecasting
                String iconDir = GetImageDirectory(TodayIconSize);
                String iconSrc = Page.ClientScript.GetWebResourceUrl(typeof(WeatherForecast), String.Format("{0}.{1}.png", iconDir, outlook.Icon));

                weatherContent.AppendFormat("<div class=\"{0}WcLocation\">Weather in {1}</div>", Skin, outlook.Location);
                weatherContent.AppendFormat("<table class=\"{0}WcWeatherTable\">", Skin);
                weatherContent.AppendFormat("<tr><td><img src=\"{0}\" alt=\"{1}\"/></td>", iconSrc, outlook.Description);
                weatherContent.AppendFormat("<td align=\"center\"><div class=\"{0}WcCurrentTemp\">{1}&deg; {2}</div><br />", Skin, outlook.Temperature, outlook.Units.Temperature);
                weatherContent.AppendFormat("<div class=\"{0}WcCurrentDescription\">{1}</div></td></tr>", Skin, outlook.Description);


                // Template row to hold Current Weather Properties
                String CurrentProperties = String.Format("<tr><td colspan='2'><div class=\"{0}WcCurrentProperties\">{1}", Skin, "{0}");
                bool EndPropertiesTag = false;
                // Weather Properties
                String thisProperty;

                if (ShowWindChill)
                {
                    thisProperty = BuildWeatherLabel("Feels Like", outlook.WindChill.ToString());
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}&deg;<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowWindSpeedAndDirection)
                {
                    thisProperty = BuildWeatherLabel("Wind", String.Format("{0} {1}{2}", outlook.Wind.Direction, outlook.Wind.Speed, outlook.Units.Speed));
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowDewpoint)
                {
                    thisProperty = BuildWeatherLabel("Dewpoint", outlook.Dewpoint.ToString());
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}&deg;<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowHumidity)
                {
                    thisProperty = BuildWeatherLabel("Humidity", outlook.Humidity.ToString());
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}%<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowUvIndex)
                {
                    thisProperty = BuildWeatherLabel("UV Index", String.Format("{0} ({1})", outlook.UV.Index, outlook.UV.Description));
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowVisibility)
                {
                    thisProperty = BuildWeatherLabel("Visibility", outlook.Visibility.ToString());
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}{1}<br />", thisProperty, outlook.Units.Distance));
                    EndPropertiesTag = true;
                }

                if (ShowBarometer)
                {
                    thisProperty = BuildWeatherLabel("Pressure", String.Format("{0}{1} and {2}", outlook.Barometer.Reading, outlook.Units.Pressure, outlook.Barometer.Direction));
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}<br />", thisProperty));
                    EndPropertiesTag = true;
                }

                if (ShowChanceForPrecipitation)
                {
                    String percipChance = GetChanceForPrecipitation(twcWeather, outlook.LocalTime);
                    thisProperty = BuildWeatherLabel("Chance for precipitation", percipChance);
                    weatherContent.AppendFormat(CurrentProperties, String.Format("{0}%", thisProperty));
                    EndPropertiesTag = true;
                }

                // Do we need to end our additional weather properties tag?
                if (EndPropertiesTag) weatherContent.Append("</div></td></tr>");

                //Show forecast?
                if (ShowForecast)
                {
                    String tblForecast = GetForecastText(twcWeather, outlook.LocalTime.ToString());
                    weatherContent.AppendFormat("<tr><td colspan='2' align='center'>{0}</td></tr>", tblForecast);
                }

                weatherContent.Append("</table>");
            }
            return weatherContent;
        }

        private String GetForecastText(weather twcWeather, String LocalTime)
        {
            StringBuilder sbForecast = new StringBuilder();
            sbForecast.AppendFormat("<table class=\"{0}WcForecastTable\">", Skin);

            int dayPartToShow = 0;
            String forecastIcon, forecastTooltip;

            // Loop through forecast by rows: forecast image, high, then low as table rows
            int rowNum = 0;
            while (rowNum < 4)
            {
                sbForecast.AppendFormat("<tr class=\"{0}WcForecastRow{1}\">", Skin, rowNum);

                for (int y = 0; y < ForecastDaysToDisplay; y++)
                {
                    if (y == 0)
                        dayPartToShow = GetDayPartToShow(LocalTime);
                    else
                        dayPartToShow = (int)DayPart.Day;

                    WeatherForecast forecast = new WeatherForecast(twcWeather, y.ToString());

                    switch (rowNum)
                    {
                        default:
                        case 0: // Day Header Row
                            if (ShowDayInForecast)
                                sbForecast.AppendFormat("<td><div title=\"{0}\">{1}</div></td>", forecast.ForecastDate, forecast.ForecastShortDay);
                            break;

                        case 1: // Forecast Icon Row
                            if (dayPartToShow == (int)DayPart.Day)
                            {
                                forecastIcon = forecast.DayDetails.Icon.ToString();
                                forecastTooltip = String.Format(FORECAST_TOOLTIP, forecast.DayDetails.Description, LINE_BREAK, forecast.Sunrise, forecast.Sunset, forecast.DayDetails.Humidity, forecast.DayDetails.PrecipChance);
                            }
                            else
                            {
                                forecastIcon = forecast.NightDetails.Icon.ToString();
                                forecastTooltip = String.Format(FORECAST_TOOLTIP, forecast.NightDetails.Description, LINE_BREAK, forecast.Sunrise, forecast.Sunset, forecast.NightDetails.Humidity, forecast.NightDetails.PrecipChance);
                            }

                            // What size of image are we loading?
                            String iconDir = GetImageDirectory(ForecastIconSize);
                            String iconSrc = Page.ClientScript.GetWebResourceUrl(typeof(WeatherForecast), String.Format("{0}.{1}.png", iconDir, forecastIcon));
                            sbForecast.AppendFormat("<td><img src='{0}' alt='Forecast' title='{1}'/></td>", iconSrc, forecastTooltip);
                            break;

                        case 2: // Forecast High Row
                            String deg;
                            if (forecast.High == "N/A")
                                deg = "";
                            else
                                deg = "&deg;";
                            sbForecast.AppendFormat("<td>{0}{1}</td>", forecast.High, deg);
                            break;

                        case 3: // Forecast Low Row
                            sbForecast.AppendFormat("<td>{0}&deg;</td>", forecast.Low);
                            break;
                    }
                }

                sbForecast.Append("</tr>");
                rowNum += 1;
            }

            sbForecast.Append("</table>");
            return sbForecast.ToString();
        }

        private void PerformLocationSearch(String query)
        {
            if (String.IsNullOrEmpty(query))
                return;

            List<LocationDetail> searchResults = new List<LocationDetail>();

            Uri searchUri = new Uri(String.Format("http://xoap.weather.com/search/search?where={0}", query), UriKind.Absolute);
            XmlDocument twcSearch = WeatherManager.LoadTwcSearchIntoXmlDoc(searchUri, EnableCaching, query);
            search results = TwcWeatherManager.GetTwcSearchResults(twcSearch);

            LocationDetail locationDetail;
            foreach (var item in results.loc)
            {
                locationDetail = new LocationDetail();
                locationDetail.LocationId = item.id;
                locationDetail.LocationName = item.Value;

                if (!String.IsNullOrEmpty(locationDetail.LocationId))
                    searchResults.Add(locationDetail);

                if (results.loc.Count() == 1)
                    LocationId = locationDetail.LocationId;
            }

            SearchResults = searchResults;
        }

        private static int GetDayPartToShow(String LocalTime)
        {
            // Show night forecast for current day if local time is past 2pm
            if (LocalTime.IndexOf("P") > -1 && DateTime.Parse(LocalTime).Hour >= 14)
                return (int)DayPart.Night;
            else
                return (int)DayPart.Day;
        }

        private static String GetLinks(XmlDocument xmlDoc)
        {
            String lnkNode = "/weather/lnks";
            XmlNode xmlNode = xmlDoc.SelectSingleNode(lnkNode);

            StringBuilder sbLinks = new StringBuilder();
            String lnkHref, lnkText = null;

            if ((xmlNode != null))
            {
                for (int x = 0; x <= xmlNode.ChildNodes.Count; x++)
                {
                    lnkHref = XmlParser.GetNodeText(xmlDoc, String.Format("{0}/link[@pos=\"{1}\"]/l", lnkNode, x));
                    lnkText = XmlParser.GetNodeText(xmlDoc, String.Format("{0}/link[@pos=\"{1}\"]/t", lnkNode, x));
                    if (!(String.IsNullOrEmpty(lnkHref) && String.IsNullOrEmpty(lnkText)))
                        sbLinks.AppendFormat("<a href=\"{0}\">{1}</a><br />", lnkHref, lnkText);
                }
            }

            return sbLinks.ToString();
        }

        private static String GetChanceForPrecipitation(weather twcWeather, String LocalTime)
        {
            int dayPartToShow = GetDayPartToShow(LocalTime);
            String dayChar = dayPartToShow == (int)DayPart.Day ? "d" : "n";
            return twcWeather.dayf.day[0].part.Where(p => p.p == dayChar).FirstOrDefault().ppcp.ToString();
        }

        private static String BuildWeatherLabel(String weatherLabel, String value)
        {
            return String.Format("{0}: {1}", weatherLabel, value);
        }

        private static String GetImageDirectory(ImageSize imgSize)
        {
            switch (imgSize)
            {
                case ImageSize.Small:
                    return String.Format("{0}.Small", IMAGE_NAMESPACE);
                case ImageSize.Medium:
                    return String.Format("{0}.Medium", IMAGE_NAMESPACE);
                case ImageSize.Large:
                    return String.Format("{0}.Large", IMAGE_NAMESPACE);
                case ImageSize.ExtraLarge:
                    return String.Format("{0}.ExtraLarge", IMAGE_NAMESPACE);
                default:
                    return String.Format("{0}.Small", IMAGE_NAMESPACE);
            }
        }
        #endregion
    }
}